﻿using System;
using System.Collections.Generic;

namespace TetrisGame
{
    /// <summary>
    /// 移动方向枚举
    /// </summary>
    internal enum E_MoveDirection
    {
        Left,
        Right,
        Down
    }

    internal class BlockHandler : IDraw
    {
        // 需要渲染到屏幕上的方块
        // 它装的就是四个绘制对象 因为要绘制到 屏幕上
        private List<DrawObject> blocks;

        // 存储所有方块信息的字典
        private readonly Dictionary<E_DrawType, BlockInfo> blockInfoDic;

        // 存储随机的方块信息
        private BlockInfo randomBlockInfo;

        // 随机一种方块形态的索引
        private int randomBlockPositionIndex;

        public BlockHandler()
        {
            // 初始化字典
            blockInfoDic = new Dictionary<E_DrawType, BlockInfo>();
            // 将所有方块类型添加到字典中 后面可以通过类型获取对应的方块坐标信息
            // 实例化所有方块类型的坐标信息 保存到字典中
            foreach (E_DrawType blockType in Enum.GetValues(typeof(E_DrawType)))
            {
                if (blockType != E_DrawType.Score && blockType != E_DrawType.NextTitle && blockType != E_DrawType.Wall)
                {
                    blockInfoDic.Add(blockType, new BlockInfo(blockType));
                }
            }
            // 随机创建一个方块
            RanDomCreateBlock();
        }

        public void Draw()
        {
            foreach (DrawObject block in blocks)
            {
                block.Draw(); // 绘制每个方块
            }
        }

        /// <summary>
        /// 随机创建一个方块
        /// </summary>
        public void RanDomCreateBlock()
        {
            // 随机生成一个方块类型
            Random random = new Random();
            E_DrawType blockType = (E_DrawType)random.Next((int)E_DrawType.Block, (int)E_DrawType.Right_ZShape + 1);

            // 现在有方块坐标信息，但是没有绘制方块的对象，下面就是添加绘制方块的对象，所有的方块组都是由四个小方块组成的
            // 每次创建一个方块 其实就是创建4个小方块
            // DrawObject(blockType)会调用DrawObject的构造函数 绘制blockType颜色的方块
            blocks = new List<DrawObject>
            {
                new DrawObject(blockType),
                new DrawObject(blockType),
                new DrawObject(blockType),
                new DrawObject(blockType)
            };

            // 设置每个小方块的位置
            // 原点位置 自己定义 方块list中的第0个元素就是原点位置
            // 设置原点位置为屏幕中间上方
            blocks[0].Pos = new Position(Game.Width / 2 - 1, -5);

            // 先拿到随机方块的 四种形状的坐标信息 list集合
            // 其他三个方块的位置 根据原点位置的方块来设置
            // blockInfoDic[blockType]里面有四个相同方块不同形状的坐标信息 其实就是一个list集合
            randomBlockInfo = blockInfoDic[blockType];

            // 再次随机，获取四个方块不同形状的坐标信息
            // 通过Count获取最多的形状数量
            randomBlockPositionIndex = random.Next(0, randomBlockInfo.Count);
            // 更新其他三个方块的位置
            SetOtherBlockPos();
        }

        /// <summary>
        /// 擦除所有方块
        /// </summary>
        private void ClearBlocks()
        {
            // 先清空之前的位置
            for (int i = 0; i < blocks.Count; i++)
            {
                if (blocks[i].Pos.x != 0 && blocks[i].Pos.y >= 0) // 确保不清除掉原点位置
                {
                    blocks[i].Clear(); // 清除方块
                }
            }
        }

        /// <summary>
        /// 设置其他三个方块的位置
        /// </summary>
        public void SetOtherBlockPos()
        {
            ClearBlocks();
            // 设置其他三个方块的位置
            // randomBlockInfo[randomBlockPositionIndex]里面就是四个方块的坐标信息中的一个方块的坐标信息 是一个Position数组
            Position[] positions = randomBlockInfo[randomBlockPositionIndex]; // 这里就是通过索引器获取某一种形状的坐标信息
            for (int i = 0; i < positions.Length; i++)
            {
                // 设置其他三个方块的位置 其他三个方块的位置是相对于原点位置的偏移量
                // positions[i]是一个Position结构体，里面有x和y坐标
                blocks[i + 1].Pos = blocks[0].Pos + positions[i];
            }
            Draw(); // 绘制所有方块
        }

        /// <summary>
        /// 旋转方块
        /// </summary>
        public void ChangeBlockRotation()
        {
            randomBlockPositionIndex++; // 切换到下一个形状的索引
            // 如果超过了最大形状数量，则回到第一个形状
            if (randomBlockPositionIndex >= randomBlockInfo.Count)
            {
                randomBlockPositionIndex = 0; // 回到第一个形状
            }
            // 更新其他三个方块的位置
            SetOtherBlockPos();
        }

        /// <summary>
        /// 检测是否可以旋转方块
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public bool CanChangeBlockCheck(Map map)
        {
            // 检查是否可以旋转方块
            // 检查旋转后的方块的位置是否在地图范围内
            int changedPosition = randomBlockPositionIndex; // 获取旋转后的方块位置索引 不改变原有的值
            changedPosition++; // 旋转后索引加1
            if (changedPosition >= randomBlockInfo.Count)
            {
                changedPosition = 0;
            }
            Position[] positions = randomBlockInfo[changedPosition];
            for (int i = 0; i < positions.Length; i++)
            {
                Position pos = blocks[0].Pos + positions[i];
                if (pos.x < 2 || pos.x > Game.Width - 3 || pos.y >= Game.Height - 7)
                {
                    return false;
                }
            }
            // 检查旋转后的方块的位置是否和地图上的方块重叠
            foreach (DrawObject wall in map.dynamicWalls)
            {
                for (int i = 0; i < positions.Length; i++)
                {
                    Position pos = blocks[0].Pos + positions[i];
                    if (pos == wall.Pos)
                    {
                        return false; // 有重叠，不能旋转
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 移动方块
        /// </summary>
        /// <param name="direction">方向枚举</param>
        public void MoveBlock(E_MoveDirection direction)
        {
            // 设置移动方向的偏移量
            Position offset = new Position(0, 0);
            switch (direction)
            {
                case E_MoveDirection.Left:
                    // 向左移动
                    offset = new Position(-2, 0); // 原点位置向左移动2个单位
                    break;

                case E_MoveDirection.Right:
                    // 向右移动
                    offset = new Position(2, 0); // 原点位置向右移动2个单位
                    break;

                case E_MoveDirection.Down:
                    // 向下移动
                    offset = new Position(0, 1); // 原点位置向下移动1个单位
                    break;
            }
            blocks[0].Clear(); // 清除原点位置的方块
            blocks[0].Pos += offset; // 更新原点位置
            // 更新其他三个方块的位置
            SetOtherBlockPos();
        }

        /// <summary>
        /// 检测是否可以移动方块
        /// </summary>
        /// <param name="direction">移动方向</param>
        /// <param name="map">地图类</param>
        /// <returns></returns>
        public bool CanMoveBlockCheck(E_MoveDirection direction, Map map)
        {
            // 检查是否可以移动方块
            Position offset = new Position(0, 0);
            switch (direction)
            {
                case E_MoveDirection.Left:
                    offset = new Position(-2, 0); // 向左移动
                    break;

                case E_MoveDirection.Right:
                    offset = new Position(2, 0); // 向右移动
                    break;

                case E_MoveDirection.Down:
                    offset = new Position(0, 1); // 向下移动
                    break;
            }
            // 检查移动后的方块位置是否在地图范围内
            for (int i = 0; i < blocks.Count; i++)
            {
                Position pos = blocks[i].Pos + offset;
                if (pos.x < 2 || pos.x > Game.Width - 3 || pos.y >= Game.Height - 7)
                {
                    if (direction == E_MoveDirection.Down)
                    {
                        map.AddDynamicWall(blocks); // 添加到动态墙壁中
                        Draw();
                        RanDomCreateBlock(); // 重新生成一个方块
                        return false;
                    }
                    return false; // 移动后超出地图范围，不能移动
                }
            }
            // 检查移动后的方块位置是否和地图上的方块重叠
            foreach (DrawObject wall in map.dynamicWalls)
            {
                for (int i = 0; i < blocks.Count; i++)
                {
                    Position pos = blocks[i].Pos + offset;
                    if (pos == wall.Pos)
                    {
                        if (direction == E_MoveDirection.Down)
                        {
                            map.AddDynamicWall(blocks); // 添加到动态墙壁中
                            Draw();
                            RanDomCreateBlock(); // 重新生成一个方块
                            return false;
                        }
                        return false;
                    }
                }
            }
            return true; // 可以移动
        }
    }
}